package com.yht.weblog.jwt.filter;

import com.yht.weblog.jwt.utils.JwtTokenHelper;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

/**
 * @author: yht
 * @date: 2023/12/7 20:51
 * @description: Token认证过滤器
 **/
@Slf4j
public class TokenAuthenticationFilter extends OncePerRequestFilter {


    @Value("${jwt.tokenPrefix}")
    private String tokenPrefix;

    @Value("${jwt.tokenHeaderKey}")
    private String tokenHeaderKey;

    @Autowired
    private JwtTokenHelper jwtTokenHelper;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;

    /**
     * 过滤器的内部方法，用于处理请求和响应。
     *
     * @param request     请求对象
     * @param response    响应对象
     * @param filterChain 过滤器链
     * @throws ServletException Servlet异常
     * @throws IOException      IO异常
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String requestURI = request.getRequestURI();

        if (requestURI.contains("/admin")) {

            // 获取请求头中的Authorization字段
            String header = request.getHeader(tokenHeaderKey);

            // 如果Authorization字段以Bearer开头，则提取出token
            if (StringUtils.startsWith(header, tokenPrefix)) {
                String token = StringUtils.substring(header, 7);
                log.info("Token: {}", token);

                // 如果token不为空，则验证token的有效性
                if (StringUtils.isNotBlank(token)) {
                    try {
                        // 验证token的有效性
                        jwtTokenHelper.validateToken(token);
                    } catch (SignatureException | MalformedJwtException | UnsupportedJwtException |
                             IllegalArgumentException e) {
                        authenticationEntryPoint.commence(request, response, new AuthenticationServiceException("Token 不可用"));
                        return;
                    } catch (ExpiredJwtException e) {
                        authenticationEntryPoint.commence(request, response, new AuthenticationServiceException("Token 已失效"));
                        return;
                    }

                    // 获取token中的用户名
                    String username = jwtTokenHelper.getUsernameByToken(token);

                    // 如果用户名不为空且当前SecurityContextHolder中的Authentication为空，则进行身份验证
                    if (StringUtils.isNotBlank(username) && Objects.isNull(SecurityContextHolder.getContext().getAuthentication())) {
                        // 加载用户详情信息
                        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                        // 创建UsernamePasswordAuthenticationToken对象进行身份验证
                        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                        // 将身份验证信息放入SecurityContextHolder中
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                    }
                }

            }
        }

        // 继续执行后续的过滤器链
        filterChain.doFilter(request, response);

    }
}
